<?php

namespace helper;


class Utils
{

  /**
   * 是否手机
   * @return bool
   */
  static public function isMobile()
  {
    return request()->isMobile();
  }

  /**
   * 是否为微信内部浏览器
   * @return bool
   */
  static public function isWeBrowser()
  {
    return (strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger') !== false);
  }

  /**
   * 删除html
   * @param $str
   * @return string
   */
  static public function delHtml($str)
  {
    return trim(strip_tags($str));
  }

  /**
   * 输出安全html
   * @param string $str 需要操作的字符串
   * @return string 操作后的字符串
   */
  static public function htmlOut($str)
  {
    $str    = stripslashes(htmlspecialchars_decode($str));
    $search = ["'<script[^>]*?>.*?</script>'si", "'<iframe[^>]*?>.*?</iframe>'si"];
    $str    = preg_replace($search, '', $str); //过滤script和iframe
    return $str;
  }

  /**
   * 内容分页
   * @param string $content 需要拆分的数据
   * @param string $needle 拆分后的数据
   */
  static public function contentPage($content, $needle = '_page_break_tag_')
  {
    //根据分页标识来拆分分页
    $pageContent    = explode($needle, self::htmlOut($content));
    $page           = isset($_GET['cp']) ? intval($_GET['cp']) : 0;
    $contentNowPage = $page > 0 ? $page - 1 : 0;
    echo $pageContent[$contentNowPage]; //输出当前页内容
    $currentUrl = self::currentUrl();
    $url        = strpos($currentUrl, '.html?') !== false ? $currentUrl . '&' : $currentUrl . '?';
    if (($pageCount = count($pageContent)) > 1) {
      $pageHtml = '<div class="clear"></div><div class="page">#page#</div>';
      $pageStr  = [];
      for ($i = 1; $i <= $pageCount; $i++) {
        $style = '';
        if ($page == $i) {
          $style = 'class="current"';
        }
        $pageStr[] = '<a href="' . $url . 'cp=' . $i . '" ' . $style . '>' . $i . '</a>';
      }
      $pageHtml = str_replace('#page#', implode(PHP_EOL, $pageStr), $pageHtml);
      echo $pageHtml;
    }
  }

  /**
   * 获取当前url
   * @return string 当前url
   */
  static public function currentUrl()
  {
    $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
    $url      = "{$protocol}{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}";
    return $url;
  }

  /**
   * 友好的时间显示
   * @param int $sTime 待显示的时间
   * @param string $type 类型. normal | mohu | full | ymd | other
   * @return string
   */
  static public function friendDate($sTime, $type = 'normal')
  {
    if (!$sTime) return '';
    //sTime=源时间，cTime=当前时间，dTime=时间差
    $cTime = time();
    $dTime = $cTime - $sTime;
    $dDay  = intval(date("z", $cTime)) - intval(date("z", $sTime));
    //$dDay     =   intval($dTime/3600/24);
    $dYear = intval(date("Y", $cTime)) - intval(date("Y", $sTime));
    //normal：n秒前，n分钟前，n小时前，日期
    if ($type == 'normal') {
      if ($dTime < 60) {
        if ($dTime < 10) {
          return '刚刚';    //by yangjs
        } else {
          return intval(floor($dTime / 10) * 10) . "秒前";
        }
      } elseif ($dTime < 3600) {
        return intval($dTime / 60) . "分钟前";
        //今天的数据.年份相同.日期相同.
      } elseif ($dYear == 0 && $dDay == 0) {
        //return intval($dTime/3600)."小时前";
        return '今天' . date('H:i', $sTime);
      } elseif ($dYear == 0) {
        return date("m月d日 H:i", $sTime);
      } else {
        return date("Y-m-d H:i", $sTime);
      }
    } elseif ($type == 'mohu') {
      if ($dTime < 60) {
        return $dTime . "秒前";
      } elseif ($dTime < 3600) {
        return intval($dTime / 60) . "分钟前";
      } elseif ($dTime >= 3600 && $dDay == 0) {
        return intval($dTime / 3600) . "小时前";
      } elseif ($dDay > 0 && $dDay <= 7) {
        return intval($dDay) . "天前";
      } elseif ($dDay > 7 && $dDay <= 30) {
        return intval($dDay / 7) . '周前';
      } elseif ($dDay > 30) {
        return intval($dDay / 30) . '个月前';
      }
      //full: Y-m-d , H:i:s
    } elseif ($type == 'full') {
      return date("Y-m-d , H:i:s", $sTime);
    } elseif ($type == 'ymd') {
      return date("Y-m-d", $sTime);
    } else {
      if ($dTime < 60) {
        return $dTime . "秒前";
      } elseif ($dTime < 3600) {
        return intval($dTime / 60) . "分钟前";
      } elseif ($dTime >= 3600 && $dDay == 0) {
        return intval($dTime / 3600) . "小时前";
      } elseif ($dYear == 0) {
        return date("Y-m-d H:i:s", $sTime);
      } else {
        return date("Y-m-d H:i:s", $sTime);
      }
    }
    return '';
  }

  /**
   * 人民币小写转大写
   * @param int $number 数值
   * @param string $int_unit 币种单位，默认"元"，有的需求可能为"圆"
   * @param bool $is_round 是否对小数进行四舍五入
   * @param bool $is_extra_zero 是否对整数部分以0结尾，小数存在的数字附加0,比如1960.30
   * @return string
   */
  static public function num2rmb($number = 0, $int_unit = '元', $is_round = TRUE, $is_extra_zero = FALSE)
  {
    // 将数字切分成两段
    $parts = explode('.', $number, 2);
    $int   = isset($parts[0]) ? strval($parts[0]) : '0';
    $dec   = isset($parts[1]) ? strval($parts[1]) : '';

    // 如果小数点后多于2位，不四舍五入就直接截，否则就处理
    $dec_len = strlen($dec);
    if (isset($parts[1]) && $dec_len > 2) {
      $dec = $is_round
          ? substr(strrchr(strval(round(floatval("0." . $dec), 2)), '.'), 1)
          : substr($parts[1], 0, 2);
    }

    // 当number为0.001时，小数点后的金额为0元
    if (empty($int) && empty($dec)) {
      return '零';
    }

    // 定义
    $chs     = array('0', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖');
    $uni     = array('', '拾', '佰', '仟');
    $dec_uni = array('角', '分');
    $exp     = array('', '万');
    $res     = '';

    // 整数部分从右向左找
    for ($i = strlen($int) - 1, $k = 0; $i >= 0; $k++) {
      $str = '';
      // 按照中文读写习惯，每4个字为一段进行转化，i一直在减
      for ($j = 0; $j < 4 && $i >= 0; $j++, $i--) {
        $u   = $int{$i} > 0 ? $uni[$j] : ''; // 非0的数字后面添加单位
        $str = $chs[$int{$i}] . $u . $str;
      }
      //echo $str."|".($k - 2)."<br>";
      $str = rtrim($str, '0');// 去掉末尾的0
      $str = preg_replace("/0+/", "零", $str); // 替换多个连续的0
      if (!isset($exp[$k])) {
        $exp[$k] = $exp[$k - 2] . '亿'; // 构建单位
      }
      $u2  = $str != '' ? $exp[$k] : '';
      $res = $str . $u2 . $res;
    }

    // 如果小数部分处理完之后是00，需要处理下
    $dec = rtrim($dec, '0');

    // 小数部分从左向右找
    if (!empty($dec)) {
      $res .= $int_unit;

      // 是否要在整数部分以0结尾的数字后附加0，有的系统有这要求
      if ($is_extra_zero) {
        if (substr($int, -1) === '0') {
          $res .= '零';
        }
      }

      for ($i = 0, $cnt = strlen($dec); $i < $cnt; $i++) {
        $u   = $dec{$i} > 0 ? $dec_uni[$i] : ''; // 非0的数字后面添加单位
        $res .= $chs[$dec{$i}] . $u;
      }
      $res = rtrim($res, '0');// 去掉末尾的0
      $res = preg_replace("/0+/", "零", $res); // 替换多个连续的0
    } else {
      $res .= $int_unit . '整';
    }
    return $res;
  }

  /**
   * 抓取远程图片
   * @param string $url 远程图片地址
   * @param string $filename 保存到本地地址 默认按时间戳微妙数MD5生成
   * @param string $save_dir 保存路径 默认upload/images/Ymd/ 路径
   * @return array 抓取后的数据数组
   */
  static public function saveImage($url, $filename = '', $save_dir = '')
  {
    if (trim($url) == '') {
      return ['msg' => '远程地址不能为空！', 'code' => 0];
    }
    if (trim($save_dir) == '') {
      $save_dir = './upload/images/' . date('Ymd') . '/';
      //创建保存目录
      if (!file_exists($save_dir) && !mkdir($save_dir, 0777, true)) {
        return ['msg' => '文件目录不可写！', 'code' => 0];
      }
      Files::createDir($save_dir); //递归创建保存文件夹
    }
    if (trim($filename) == '') {
      //文件头获取文件名
      $mimes = [
          'image/bmp' => '.bmp',
          'image/gif' => '.gif',
          'image/jpeg' => '.jpg',
          'image/png' => '.png',
          'image/x-icon' => '.ico',
      ];
      if (($headers = get_headers($url, 1)) !== false) {
        $type = $headers['Content-Type'];
        $ext  = $mimes[$type];
        if ($ext != '.gif' && $ext != '.jpg' && $ext != '.png' && $ext != '.jpeg') {
          return ['msg' => '文件格式不正确！', 'code' => 0];
        }
      } else {
        return ['msg' => '未找到文件头！', 'code' => 0];
      }
      $filename = md5(microtime(true)) . $ext;
    }
    ob_start();
    readfile($url);
    $img = ob_get_contents();
    ob_end_clean();
    //文件大小
    $fp2 = @fopen($save_dir . $filename, 'a');
    fwrite($fp2, $img);
    fclose($fp2);
    unset($img, $url);
    return ['file_name' => $filename, 'save_path' => $save_dir . $filename];
  }

  /**
   * 图片转base64
   * @param string $url
   * @param int $timeout
   * @return bool|string
   */
  static public function image2Base64($url = '', $timeout = 10)
  {
    $imageInfo = getimagesize($url);
    return 'data:' . $imageInfo['mime'] . ';base64,' . chunk_split(base64_encode(file_get_contents($url)));
  }

  /**
   * base64图片转存
   * @param $base64
   * @param $fileName
   * @return bool|string
   */
  static public function base642image($base64, $fileName)
  {
    //匹配出图片的格式
    if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $base64, $result)) {
      $type     = $result[2];
      $pathInfo = pathinfo($fileName);
      $path     = app()->getRootPath() . 'public/' . $pathInfo['dirname'];
      if (!file_exists($path)) Files::createDir($path);
      $file = "{$pathInfo['filename']}.{$type}";
      if (file_put_contents($path . '/' . $file, base64_decode(str_replace($result[1], '', $base64)))) {
        return '/' . $pathInfo['dirname'] . '/' . $file;
      }
    }
    return false;
  }

  /**
   * 把从HTML源码中获取的相对路径转换成绝对路径
   * @param string $url HTML中获取的网址
   * @param string $baseUrl 用来参考判断的原始地址
   * @return bool|false|string|string[]|null 返回修改过的网址，如果网址有误则返回false
   */
  static public function filterRelativeUrl($url, $baseUrl)
  {
    //STEP1: 先去判断URL中是否包含协议，如果包含说明是绝对地址则可以原样返回
    if (strpos($url, '://') !== false) return $url;
    //STEP2: 解析传入的URI
    if (substr($baseUrl, -1) == '/') $baseUrl .= 'index.html'; //最后一位为/时人为补充一个文件名称
    $urlPart = parse_url($baseUrl);
    if ($urlPart == FALSE) return false;
    $rootUrl = $urlPart['scheme'] . '://' . $urlPart['host'] . (isset($urlPart['port']) ? ':' . $urlPart['port'] : '');
    //STEP3: 如果URL以左斜线开头，表示位于根目录
    if (strpos($url, '/') === 0) {
      return $rootUrl . $url;
    }
    //STEP4: 不位于根目录，也不是绝对路径，考虑如果不包含'./'的话，需要把相对地址接在原URL的目录名上
    $urlDir = (isset($urlPart['path']) && $urlPart['path']) ? '/' . ltrim(dirname($urlPart['path']), '/') : '';
    if (strpos($url, './') === FALSE) {
      if ($urlDir != '') {
        return $rootUrl . $urlDir . '/' . $url;
      } else {
        return $rootUrl . '/' . $url;
      }
    }
    //STEP5: 如果相对路径中包含'../'或'./'表示的目录，需要对路径进行解析并递归
    //STEP5.1: 把路径中所有的'./'改为'/'，'//'改为'/'
    $url = preg_replace('/[^\.]\.\/|\/\//', '/', $url);
    if (strpos($url, './') === 0)
      $url = substr($url, 2);
    //STEP5.2: 使用'/'分割URL字符串以获取目录的每一部分进行判断
    $urlFullDir = ltrim($urlDir . '/' . $url, '/');
    $urlArr     = explode('/', $urlFullDir);
    if ($urlArr[0] == '..') return false;
    //因为数组的第一个元素不可能为'..'，所以这里从第二个元素开始循环
    $dstArr = $urlArr;  //拷贝一个副本，用于最后组合URL
    for ($i = 1; $i < count($urlArr); $i++) {
      if ($urlArr[$i] == '..') {
        $j = 1;
        while (TRUE) {
          if (isset($dstArr[$i - $j]) && $dstArr[$i - $j] != false) {
            $dstArr[$i - $j] = false;
            $dstArr[$i]      = false;
            break;
          } else {
            $j++;
          }
        }
      }
    }
    // 组合最后的URL并返回
    $dstStr = $rootUrl;
    foreach ($dstArr as $val) {
      if ($val != FALSE) $dstStr .= '/' . $val;
    }
    return $dstStr;
  }

  /**
   * 把秒数转换为时分秒的格式
   * @param $times
   * @return string
   */
  static public function secToTime($times){
    $result = '00:00:00';
    if ($times>0) {
      $hour = floor($times/3600);
      $minute = floor(($times-3600 * $hour)/60);
      $second = floor((($times-3600 * $hour) - 60 * $minute) % 60);
      $result = sprintf("%02d",$hour).':'.sprintf("%02d",$minute).':'.sprintf("%02d",$second);
    }
    return $result;
  }

}
